//AUTHOR: Praveen Kambam Sugavanam
//CS5103 - Proj 2
//Last updated: 03/21/2012 - 3:39am
//


#include <stdio.h>
//#include <iostream>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
#include "scheduler.cpp"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream>
#include <string>
using namespace std;

void* mainOSThread(void* ptr);
// node for maintaining the pid queue within the IO threads.
typedef struct node 
{
     int pid;
     node* next;
}node ;

typedef struct node_holder
{
     node* head;
     node* tail;
}node_holder;

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;

bool charIO=false,blockIO=false; 

int doCharIO=0;
//mode : kernel/user

int mode; int replacementPolicy;
//queues for the charIO and block IO threads.


// timer delays
const int clockDelay = 250000;
const int charIODelay = clockDelay*4,blockIODelay = clockDelay*8;


int main(int argc, char* argv[])
{

     pthread_t thread1, thread2, thread3;
     char *message1 = "Thread 1";
     char *message2 = "Thread 2";
     int  iret1, iret2,iret3;
   
     if (argc == 3) {
       if (strcmp(argv[1],"-policy") == 0) {
	 if (strcmp(argv[2],"workingset") == 0) {
	   replacementPolicy = PG_WORKINGSET;
	 } else if (strcmp(argv[2],"approx") == 0) {
	   replacementPolicy = PG_LRUAPPROX;
	 } else if (strcmp(argv[2],"fifo") == 0) {
	   replacementPolicy = PG_FIFO;
	 } else {
	   replacementPolicy = PG_LRUPURE;
	 }
       }
     }

    /* Create independent threads each of which will execute function */
    

     iret1 = pthread_create( &thread1, NULL, mainOSThread, (void*) message1);
   
     
     pthread_join( thread1, NULL);
    
     return 0;
   
}




void* mainOSThread(void* ptr)
{
   
  cout << endl;
  cout << "Starting..." << endl;
  //char trace[256] = "main.trace";
  
  int return_code;
  return_code = SRET_SUCCESS;
  Scheduler* s = new Scheduler();
  PageTable* globalPT = s->returnPageTable(); // get global PT for LRU Approx
  MMU* globalMMU = s-> returnMMU(); // get mmu reference
  globalMMU->setPolicy(replacementPolicy); // Set policy to reflect cmd line

  int i = 0;
  int counter = 0;
  int numProcesses = 0;

//  string line;
  char line[256];
  ifstream myfile ("start.trace");
  if (myfile.is_open())
  {
    while (myfile.getline(line,256).good())
    {
      cout << "File Found: " << line << endl;
      Process* p = new Process(line);    
      numProcesses++;  
      s->AddProcess(s->getPid(), p);      
    }
    myfile.close();
  }
  
  // number of MM frames allowed for each process (MM Size / # processes)
  globalMMU->setFramesPerProcess(M/numProcesses);
  s->setBaseBound();  

  cout << endl;

  while (return_code != SRET_NO_PROCESSES)
  {
     printf("Clocktick: %d\n",i);
     cout << "Calling s->run(" << i << ");" << endl;
     return_code = s->run(i);
     i++;
     if(return_code == SRET_CS_PF)
     {
       // do something
     }
     else if (return_code == SRET_ERROR)
     {
       printf("Encountered an unexpected error. Exiting..\n");
       break;
     }        
     
     usleep(clockDelay);

     cout << endl;
  }

  // For Analysis
  cout << endl;
  cout << endl;
  cout << "Analysis:" << endl;
  cout << "Page Fault:\t" << s->returnPageFaultCount() << endl;
  cout << "Switch Count:\t" << s->returnSwitchCount() << endl;
  cout << "TLB Hits:\t" << s->returnMMU()->returnTlbHitCount() << endl;
  cout << "TLB Miss:\t" << s->returnMMU()->returnTlbMissCount() << endl;
  cout << "Page In:\t" << s->returnMMU()->returnPageInCount() << endl;
  cout << "Page Out:\t" << s->returnMMU()->returnPageOutCount() << endl;
  cout << endl;

  cout << "No Processes Remaining: Exiting" << endl;

}


